home *** CD-ROM | disk | FTP | other *** search
/ Qoole for Quake / Qoole for Quake (USA) / Qoole for Quake (USA).bin / Tutorial / HTML / QUBE.ZIP / SRC / QBSP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-05  |  27.6 KB  |  1,313 lines

  1. /* bsp5.c */
  2.  
  3. #include "bsp5.h"
  4. #include "curs.h"
  5.  
  6. /* */
  7. /* command line flags */
  8. /* */
  9. qboolean    drawflag;
  10. qboolean nofill;
  11. qboolean notjunc;
  12. qboolean noclip;
  13. qboolean onlyents;
  14. qboolean    verbose = true;
  15. qboolean    allverbose;
  16. qboolean    usehulls;
  17.  
  18. brushset_t    *brushset;
  19.  
  20. int        valid;
  21.  
  22. char    bspfilename[1024];
  23. char    pointfilename[1024];
  24. char    portfilename[1024];
  25. char    hullfilename[1024];
  26. char    logfilename[1024];
  27.  
  28. char    projectpath[1024];        /* with a trailing slash */
  29.  
  30. char    *argv0;                    /* changed after fork(); */
  31.  
  32. qboolean    worldmodel;
  33.  
  34. int        hullnum;
  35.  
  36. FILE        *LogFile;
  37.  
  38. qboolean    lightbsp = 0;            /* Light bsp file when done? */
  39. qboolean    lightbspfast = 0;        /* Quick light bsp only? */
  40. qboolean        visbsp = 0;                     /* Vis bsp file when done? */
  41. qboolean    visbspfast = 0;         /* Quick vis bsp only? */
  42.  
  43. int        majorpercent = 0;        /* How much has *really* been done */
  44.  
  45. /*=========================================================================== */
  46.  
  47. void qprintf (char *fmt, ...)
  48. {
  49.     va_list argptr;
  50.     char text[1024];
  51.  
  52.     if (!verbose)
  53.         return;
  54.  
  55.     va_start (argptr, fmt);
  56.     vsprintf (text, fmt, argptr);
  57.     va_end (argptr);
  58.  
  59.     ShowTempEntry("%s", text);
  60. }
  61.  
  62. /*
  63. =================
  64. BaseWindingForPlane
  65. =================
  66. */
  67. winding_t *BaseWindingForPlane (plane_t *p)
  68. {
  69.     int        i, x;
  70.     double    max, v;
  71.     vec3_t    org, vright, vup;
  72.     winding_t    *w;
  73.     
  74. /* find the major axis */
  75.  
  76.     max = -BOGUS_RANGE;
  77.     x = -1;
  78.     for (i=0 ; i<3; i++)
  79.     {
  80.         v = fabs(p->normal[i]);
  81.         if (v > max)
  82.         {
  83.             x = i;
  84.             max = v;
  85.         }
  86.     }
  87.     if (x==-1)
  88.         Error ("BaseWindingForPlane: no axis found");
  89.         
  90.     VectorCopy (vec3_origin, vup);    
  91.     switch (x)
  92.     {
  93.     case 0:
  94.     case 1:
  95.         vup[2] = 1;
  96.         break;        
  97.     case 2:
  98.         vup[0] = 1;
  99.         break;        
  100.     }
  101.  
  102.     v = DotProduct (vup, p->normal);
  103.     VectorMA (vup, -v, p->normal, vup);
  104.     VectorNormalize (vup);
  105.         
  106.     VectorScale (p->normal, p->dist, org);
  107.     
  108.     CrossProduct (vup, p->normal, vright);
  109.     
  110.     VectorScale (vup, 8192, vup);
  111.     VectorScale (vright, 8192, vright);
  112.  
  113. /* project a really big    axis aligned box onto the plane */
  114.     w = NewWinding (4);
  115.     
  116.     VectorSubtract (org, vright, w->points[0]);
  117.     VectorAdd (w->points[0], vup, w->points[0]);
  118.     
  119.     VectorAdd (org, vright, w->points[1]);
  120.     VectorAdd (w->points[1], vup, w->points[1]);
  121.     
  122.     VectorAdd (org, vright, w->points[2]);
  123.     VectorSubtract (w->points[2], vup, w->points[2]);
  124.     
  125.     VectorSubtract (org, vright, w->points[3]);
  126.     VectorSubtract (w->points[3], vup, w->points[3]);
  127.     
  128.     w->numpoints = 4;
  129.     
  130.     return w;    
  131. }
  132.  
  133.  
  134.  
  135. /*
  136. ==================
  137. CopyWinding
  138. ==================
  139. */
  140. winding_t    *CopyWinding (winding_t *w)
  141. {
  142.     int            size;
  143.     winding_t    *c;
  144.     
  145.     size = (int)((winding_t *)0)->points[w->numpoints];
  146.     c = malloc (size);
  147.     memcpy (c, w, size);
  148.     return c;
  149. }
  150.  
  151.  
  152.  
  153. /*
  154. ==================
  155. CheckWinding
  156.  
  157. Check for possible errors
  158. ==================
  159. */
  160. void CheckWinding (winding_t *w)
  161. {
  162. }
  163.  
  164.  
  165. /*
  166. ==================
  167. ClipWinding
  168.  
  169. Clips the winding to the plane, returning the new winding on the positive side
  170. Frees the input winding.
  171. If keepon is true, an exactly on-plane winding will be saved, otherwise
  172. it will be clipped away.
  173. ==================
  174. */
  175. winding_t *ClipWinding (winding_t *in, plane_t *split, qboolean keepon)
  176. {
  177.     double    dists[MAX_POINTS_ON_WINDING];
  178.     int        sides[MAX_POINTS_ON_WINDING];
  179.     int        counts[3];
  180.     double    dot;
  181.     int        i, j;
  182.     double    *p1, *p2;
  183.     vec3_t    mid;
  184.     winding_t    *neww;
  185.     int        maxpts;
  186.     
  187.     counts[0] = counts[1] = counts[2] = 0;
  188.  
  189. /* determine sides for each point */
  190.     for (i=0 ; i<in->numpoints ; i++)
  191.     {
  192.         dot = DotProduct (in->points[i], split->normal);
  193.         dot -= split->dist;
  194.         dists[i] = dot;
  195.         if (dot > ON_EPSILON)
  196.             sides[i] = SIDE_FRONT;
  197.         else if (dot < -ON_EPSILON)
  198.             sides[i] = SIDE_BACK;
  199.         else
  200.         {
  201.             sides[i] = SIDE_ON;
  202.         }
  203.         counts[sides[i]]++;
  204.     }
  205.     sides[i] = sides[0];
  206.     dists[i] = dists[0];
  207.     
  208.     if (keepon && !counts[0] && !counts[1])
  209.         return in;
  210.         
  211.     if (!counts[0])
  212.     {
  213.         FreeWinding (in);
  214.         return NULL;
  215.     }
  216.     if (!counts[1])
  217.         return in;
  218.     
  219.     maxpts = in->numpoints+4;    /* can't use counts[0]+2 because */
  220.                                 /* of fp grouping errors */
  221.     neww = NewWinding (maxpts);
  222.         
  223.     for (i=0 ; i<in->numpoints ; i++)
  224.     {
  225.         p1 = in->points[i];
  226.         
  227.         if (sides[i] == SIDE_ON)
  228.         {
  229.             VectorCopy (p1, neww->points[neww->numpoints]);
  230.             neww->numpoints++;
  231.             continue;
  232.         }
  233.     
  234.         if (sides[i] == SIDE_FRONT)
  235.         {
  236.             VectorCopy (p1, neww->points[neww->numpoints]);
  237.             neww->numpoints++;
  238.         }
  239.         
  240.         if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
  241.             continue;
  242.             
  243.     /* generate a split point */
  244.         p2 = in->points[(i+1)%in->numpoints];
  245.         
  246.         dot = dists[i] / (dists[i]-dists[i+1]);
  247.         for (j=0 ; j<3 ; j++)
  248.         {    /* avoid round off error when possible */
  249.             if (split->normal[j] == 1)
  250.                 mid[j] = split->dist;
  251.             else if (split->normal[j] == -1)
  252.                 mid[j] = -split->dist;
  253.             else
  254.                 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
  255.         }
  256.             
  257.         VectorCopy (mid, neww->points[neww->numpoints]);
  258.         neww->numpoints++;
  259.     }
  260.     
  261.     if (neww->numpoints > maxpts)
  262.         Error ("ClipWinding: points exceeded estimate");
  263.         
  264. /* free the original winding */
  265.     FreeWinding (in);
  266.     
  267.     return neww;
  268. }
  269.  
  270.  
  271. /*
  272. ==================
  273. DivideWinding
  274.  
  275. Divides a winding by a plane, producing one or two windings.  The
  276. original winding is not damaged or freed.  If only on one side, the
  277. returned winding will be the input winding.  If on both sides, two
  278. new windings will be created.
  279. ==================
  280. */
  281. void    DivideWinding (winding_t *in, plane_t *split, winding_t **front, winding_t **back)
  282. {
  283.     double    dists[MAX_POINTS_ON_WINDING];
  284.     int        sides[MAX_POINTS_ON_WINDING];
  285.     int        counts[3];
  286.     double    dot;
  287.     int        i, j;
  288.     double    *p1, *p2;
  289.     vec3_t    mid;
  290.     winding_t    *f, *b;
  291.     int        maxpts;
  292.     
  293.     counts[0] = counts[1] = counts[2] = 0;
  294.  
  295. /* determine sides for each point */
  296.     for (i=0 ; i<in->numpoints ; i++)
  297.     {
  298.         dot = DotProduct (in->points[i], split->normal);
  299.         dot -= split->dist;
  300.         dists[i] = dot;
  301.         if (dot > ON_EPSILON)
  302.             sides[i] = SIDE_FRONT;
  303.         else if (dot < -ON_EPSILON)
  304.             sides[i] = SIDE_BACK;
  305.         else
  306.         {
  307.             sides[i] = SIDE_ON;
  308.         }
  309.         counts[sides[i]]++;
  310.     }
  311.     sides[i] = sides[0];
  312.     dists[i] = dists[0];
  313.     
  314.     *front = *back = NULL;
  315.  
  316.     if (!counts[0])
  317.     {
  318.         *back = in;
  319.         return;
  320.     }
  321.     if (!counts[1])
  322.     {
  323.         *front = in;
  324.         return;
  325.     }
  326.  
  327.     maxpts = in->numpoints+4;    /* can't use counts[0]+2 because */
  328.                                 /* of fp grouping errors */
  329.  
  330.     *front = f = NewWinding (maxpts);
  331.     *back = b = NewWinding (maxpts);
  332.         
  333.     for (i=0 ; i<in->numpoints ; i++)
  334.     {
  335.         p1 = in->points[i];
  336.         
  337.         if (sides[i] == SIDE_ON)
  338.         {
  339.             VectorCopy (p1, f->points[f->numpoints]);
  340.             f->numpoints++;
  341.             VectorCopy (p1, b->points[b->numpoints]);
  342.             b->numpoints++;
  343.             continue;
  344.         }
  345.     
  346.         if (sides[i] == SIDE_FRONT)
  347.         {
  348.             VectorCopy (p1, f->points[f->numpoints]);
  349.             f->numpoints++;
  350.         }
  351.         if (sides[i] == SIDE_BACK)
  352.         {
  353.             VectorCopy (p1, b->points[b->numpoints]);
  354.             b->numpoints++;
  355.         }
  356.  
  357.         if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
  358.             continue;
  359.             
  360.     /* generate a split point */
  361.         p2 = in->points[(i+1)%in->numpoints];
  362.         
  363.         dot = dists[i] / (dists[i]-dists[i+1]);
  364.         for (j=0 ; j<3 ; j++)
  365.         {    /* avoid round off error when possible */
  366.             if (split->normal[j] == 1)
  367.                 mid[j] = split->dist;
  368.             else if (split->normal[j] == -1)
  369.                 mid[j] = -split->dist;
  370.             else
  371.                 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
  372.         }
  373.             
  374.         VectorCopy (mid, f->points[f->numpoints]);
  375.         f->numpoints++;
  376.         VectorCopy (mid, b->points[b->numpoints]);
  377.         b->numpoints++;
  378.     }
  379.     
  380.     if (f->numpoints > maxpts || b->numpoints > maxpts)
  381.         Error ("ClipWinding: points exceeded estimate");
  382. }
  383.  
  384.  
  385. /*=========================================================================== */
  386.  
  387. int            c_activefaces, c_peakfaces;
  388. int            c_activesurfaces, c_peaksurfaces;
  389. int            c_activewindings, c_peakwindings;
  390. int            c_activeportals, c_peakportals;
  391.  
  392. void PrintMemory (void)
  393. {
  394.     ShowTempEntry ("faces   : %6i (%6i)", c_activefaces, c_peakfaces);
  395.     ShowTempEntry ("surfaces: %6i (%6i)", c_activesurfaces, c_peaksurfaces);
  396.     ShowTempEntry ("windings: %6i (%6i)", c_activewindings, c_peakwindings);
  397.     ShowTempEntry ("portals : %6i (%6i)", c_activeportals, c_peakportals);
  398. }
  399.  
  400. /*
  401. ==================
  402. NewWinding
  403. ==================
  404. */
  405. winding_t *NewWinding (int points)
  406. {
  407.     winding_t    *w;
  408.     int            size;
  409.     
  410.     if (points > MAX_POINTS_ON_WINDING)
  411.         Error ("NewWinding: %i points", points);
  412.     
  413.     c_activewindings++;
  414.     if (c_activewindings > c_peakwindings)
  415.         c_peakwindings = c_activewindings;
  416.  
  417.     size = (int)((winding_t *)0)->points[points];
  418.     w = malloc (size);
  419.     memset (w, 0, size);
  420.     
  421.     return w;
  422. }
  423.  
  424.  
  425. void FreeWinding (winding_t *w)
  426. {
  427.     c_activewindings--;
  428.     free (w);
  429. }
  430.  
  431.  
  432.  
  433. /*
  434. ===========
  435. AllocFace
  436. ===========
  437. */
  438. face_t *AllocFace (void)
  439. {
  440.     face_t    *f;
  441.     
  442.     c_activefaces++;
  443.     if (c_activefaces > c_peakfaces)
  444.         c_peakfaces = c_activefaces;
  445.         
  446.     f = malloc (sizeof(face_t));
  447.     memset (f, 0, sizeof(face_t));
  448.     f->planenum = -1;
  449.  
  450.     return f;
  451. }
  452.  
  453.  
  454. void FreeFace (face_t *f)
  455. {
  456.     c_activefaces--;
  457. /*    memset (f,0xff,sizeof(face_t)); */
  458.     free (f);
  459. }
  460.  
  461.  
  462. /*
  463. ===========
  464. AllocSurface
  465. ===========
  466. */
  467. surface_t *AllocSurface (void)
  468. {
  469.     surface_t    *s;
  470.     
  471.     s = malloc (sizeof(surface_t));
  472.     memset (s, 0, sizeof(surface_t));
  473.     
  474.     c_activesurfaces++;
  475.     if (c_activesurfaces > c_peaksurfaces)
  476.         c_peaksurfaces = c_activesurfaces;
  477.         
  478.     return s;
  479. }
  480.  
  481. void FreeSurface (surface_t *s)
  482. {
  483.     c_activesurfaces--;
  484.     free (s);
  485. }
  486.  
  487. /*
  488. ===========
  489. AllocPortal
  490. ===========
  491. */
  492. portal_t *AllocPortal (void)
  493. {
  494.     portal_t    *p;
  495.     
  496.     c_activeportals++;
  497.     if (c_activeportals > c_peakportals)
  498.         c_peakportals = c_activeportals;
  499.     
  500.     p = malloc (sizeof(portal_t));
  501.     memset (p, 0, sizeof(portal_t));
  502.     
  503.     return p;
  504. }
  505.  
  506. void FreePortal (portal_t *p)
  507. {
  508.     c_activeportals--;
  509.     free (p);
  510. }
  511.  
  512.  
  513. /*
  514. ===========
  515. AllocNode
  516. ===========
  517. */
  518. node_t *AllocNode (void)
  519. {
  520.     node_t    *n;
  521.     
  522.     n = malloc (sizeof(node_t));
  523.     memset (n, 0, sizeof(node_t));
  524.     
  525.     return n;
  526. }
  527.  
  528. /*
  529. ===========
  530. AllocBrush
  531. ===========
  532. */
  533. brush_t *AllocBrush (void)
  534. {
  535.     brush_t    *b;
  536.     
  537.     b = malloc (sizeof(brush_t));
  538.     memset (b, 0, sizeof(brush_t));
  539.     
  540.     return b;
  541. }
  542.  
  543. /*=========================================================================== */
  544.  
  545. /*
  546. ===============
  547. ProcessEntity
  548. ===============
  549. */
  550. void ProcessEntity (int entnum)
  551. {
  552.     entity_t *ent;
  553.     char    mod[80];
  554.     surface_t    *surfs;
  555.     node_t        *nodes;
  556.     brushset_t    *bs;
  557.     int        count;
  558.  
  559.     ent = &entities[entnum];
  560.     if (!ent->brushes)
  561.         return;        /* non-bmodel entity */
  562.  
  563.     if (entnum > 0)
  564.     {
  565.         worldmodel = false;
  566.         if (entnum == 1)
  567.             ShowStatusEntry("Internal Entities.");
  568.                 sprintf (mod, "*%i", nummodels);
  569.         if (verbose)
  570.             PrintEntity (ent);
  571.  
  572.         if (hullnum == 0)
  573.             ShowTempEntry("Model: %s\n", mod);
  574.         SetKeyValue (ent, "model", mod);
  575.     }
  576.     else
  577.         worldmodel = true;
  578.     
  579.  
  580. /* */
  581. /* take the brush_ts and clip off all overlapping and contained faces, */
  582. /* leaving a perfect skin of the model with no hidden faces */
  583. /* */
  584.     bs = Brush_LoadEntity (ent, hullnum);
  585.     
  586.     if (!bs->brushes)
  587.     {
  588.         PrintEntity (ent);
  589.         Error ("Entity with no valid brushes");
  590.     }
  591.     
  592.     brushset = bs;
  593.     surfs = CSGFaces (bs);
  594.  
  595.     if (hullnum != 0)
  596.     {
  597.         nodes = SolidBSP (surfs, true);
  598.         if (entnum == 0 && !nofill)    /* assume non-world bmodels are simple */
  599.         {
  600.             PortalizeWorld (nodes);
  601.             if (FillOutside (nodes))
  602.             {
  603.                 surfs = GatherNodeFaces (nodes);
  604.                 nodes = SolidBSP (surfs, false);    /* make a really good tree */
  605.             }
  606.             FreeAllPortals (nodes);
  607.         }
  608.         WriteNodePlanes (nodes);
  609.         WriteClipNodes (nodes);
  610.         BumpModel (hullnum);
  611.     }
  612.     else
  613.     {
  614.     /* */
  615.     /* SolidBSP generates a node tree */
  616.     /* */
  617.     /* if not the world, make a good tree first */
  618.     /* the world is just going to make a bad tree */
  619.     /* because the outside filling will force a regeneration later */
  620.     ShowTempEntry("Generating a node tree.");
  621.                 nodes = SolidBSP (surfs, entnum == 0);  
  622.         
  623.     /* */
  624.     /* build all the portals in the bsp tree */
  625.     /* some portals are solid polygons, and some are paths to other leafs */
  626.     /* */
  627.     ShowTempEntry("Building portals.");
  628.         if (entnum == 0 && !nofill) /* assume non-world bmodels are simple */
  629.     {
  630.         ShowTempEntry("Portalizing.");
  631.         PortalizeWorld (nodes);
  632.  
  633.         ShowTempEntry("Filling outside.");
  634.             if (FillOutside (nodes))
  635.             {
  636.                 FreeAllPortals (nodes);
  637.  
  638.                 ShowTempEntry("Building a BSP tree of the portals.");
  639.                         /* get the remaining faces together into surfaces again */
  640.                 surfs = GatherNodeFaces (nodes);
  641.     
  642.             /* merge polygons */
  643.                 MergeAll (surfs);
  644.     
  645.             /* make a really good tree */
  646.                 nodes = SolidBSP (surfs, false);
  647.     
  648.                 ShowStatusEntry("Creating Vis tracing data.");
  649.                         /* make the real portals for vis tracing */
  650.                 PortalizeWorld (nodes);
  651.     
  652.                 ShowTempEntry("Writing Vis tracing data.");
  653.                         /* save portal file for vis tracing */
  654.                 WritePortalfile (nodes);
  655.                 
  656.             /* fix tjunctions */
  657.                 tjunc (nodes);
  658.             }
  659.             else {
  660.                 ShowWarningEntry("No Vis data generated.");
  661.                 sleep(1);
  662.                         }
  663.                         FreeAllPortals (nodes);
  664.         }
  665.  
  666.         count = WriteNodePlanes (nodes);
  667.         MakeFaceEdges (nodes, count);
  668.         WriteDrawNodes (nodes);
  669.     }
  670. }
  671.  
  672. /*
  673. =================
  674. UpdateEntLump
  675.  
  676. =================
  677. */
  678. void UpdateEntLump (void)
  679. {
  680.     int        m, entnum;
  681.     char    mod[80];
  682.         
  683.     PercentBar(0);
  684.  
  685.         ShowStatusEntry("Updating entities lump.");
  686.  
  687.         m = 1;
  688.     for (entnum = 1 ; entnum < num_entities ; entnum++)
  689.     {
  690.         PercentBar(256 * entnum / num_entities);
  691.  
  692.                 if (!entities[entnum].brushes)
  693.             continue;
  694.         sprintf (mod, "*%i", m);
  695.         SetKeyValue (&entities[entnum], "model", mod);
  696.         m++;
  697.     }
  698.  
  699.     ShowTempEntry("Loading BSP file.");
  700.     LoadBSPFile (bspfilename);
  701.     ShowTempEntry("Writing entities to strings.");
  702.         WriteEntitiesToString();
  703.     ShowTempEntry("Writing BSP file.");
  704.         WriteBSPFile (bspfilename);     
  705.  
  706.         PercentBar(0);
  707. }
  708.  
  709. /*
  710. =================
  711. WriteClipHull
  712.  
  713. Write the clipping hull out to a text file so the parent process can get it
  714. =================
  715. */
  716. void WriteClipHull (void)
  717. {
  718.     FILE    *f;
  719.     int        i;
  720.     dplane_t    *p;
  721.     dclipnode_t    *d;
  722.  
  723.     hullfilename[strlen(hullfilename)-1] = '0' + hullnum;
  724.  
  725.     ShowStatusEntry("Writing clipping hull.");
  726.     ShowTempEntry("Writing %s", hullfilename);
  727.  
  728.     f = fopen (hullfilename, "w");
  729.     if (!f)
  730.         Error ("Couldn't open %s", hullfilename);
  731.  
  732.     fprintf (f, "%i\n", nummodels);
  733.  
  734.     for (i=0 ; i<nummodels ; i++)
  735.         fprintf (f, "%i\n", dmodels[i].headnode[hullnum]);
  736.         
  737.     fprintf (f, "\n%i\n", numclipnodes);
  738.  
  739.     for (i=0 ; i<numclipnodes ; i++)
  740.     {
  741.         d = &dclipnodes[i];
  742.         p = &dplanes[d->planenum];
  743.         /* the node number is only written out for human readability */
  744.         fprintf (f, "%5i : %f %f %f %f : %5i %5i\n", i, p->normal[0], p->normal[1], p->normal[2], p->dist, d->children[0], d->children[1]);
  745.     }
  746.     
  747.     fclose (f);
  748. }
  749.  
  750. /*
  751. =================
  752. ReadClipHull
  753.  
  754. Read the files written out by the child processes
  755. =================
  756. */
  757. void ReadClipHull (int hullnum)
  758. {
  759.     FILE        *f;
  760.     int            i, j, n;
  761.     int            firstclipnode;
  762.     dplane_t    p;
  763.     dclipnode_t    *d;
  764.     int            c1, c2;
  765.     float        f1, f2, f3, f4;
  766.     int            junk;
  767.     vec3_t        norm;
  768.  
  769.     hullfilename[strlen(hullfilename)-1] = '0' + hullnum;
  770.  
  771.     f = fopen (hullfilename, "r");
  772.     if (!f)
  773.         Error ("Couldn't open %s", hullfilename);
  774.  
  775.     if (fscanf (f,"%i\n", &n) != 1)
  776.         Error ("Error parsing %s", hullfilename);
  777.  
  778.     if (n != nummodels)
  779.         Error ("ReadClipHull: hull had %i models, base had %i", n, nummodels);
  780.  
  781.     for (i=0 ; i<n ; i++)
  782.     {
  783.         fscanf (f, "%i\n", &j);
  784.         dmodels[i].headnode[hullnum] = numclipnodes + j;
  785.     }
  786.     
  787.     
  788.     fscanf (f,"\n%i\n", &n);
  789.     firstclipnode = numclipnodes;
  790.     
  791.     for (i=0 ; i<n ; i++)
  792.     {
  793.         if (numclipnodes == MAX_MAP_CLIPNODES)
  794.             Error ("ReadClipHull: MAX_MAP_CLIPNODES");
  795.         d = &dclipnodes[numclipnodes];
  796.         numclipnodes++;
  797.         if (fscanf (f,"%i : %f %f %f %f : %i %i\n", &junk, &f1, &f2, &f3, &f4, &c1, &c2) != 7)
  798.             Error ("Error parsing %s", hullfilename);
  799.         
  800.  
  801.         p.normal[0] = f1;
  802.         p.normal[1] = f2;
  803.         p.normal[2] = f3;
  804.         p.dist = f4;
  805.  
  806.         norm[0] = f1; norm[1] = f2; norm[2] = f3;     /* double precision */
  807.         p.type = PlaneTypeForNormal (norm);
  808.         
  809.         d->children[0] = c1 >= 0 ? c1 + firstclipnode : c1;
  810.         d->children[1] = c2 >= 0 ? c2 + firstclipnode : c2;
  811.         d->planenum = FindFinalPlane (&p);
  812.     }
  813.     
  814. }
  815.  
  816. /*
  817. =================
  818. CreateSingleHull
  819.  
  820. =================
  821. */
  822. void CreateSingleHull (void)
  823. {
  824.     int            entnum;
  825.     float            curpercent;
  826.  
  827.     /* for each entity in the map file that has geometry */
  828.     for (entnum = 0 ; entnum < num_entities ; entnum++) {
  829.         verbose = false;        /* Don't print anything */
  830.                 ProcessEntity (entnum);
  831.  
  832.         curpercent = 32 * entnum / num_entities;
  833.         MajorPercentBar((majorpercent+curpercent)*256/100);
  834.         }
  835.  
  836.     if (hullnum)
  837.         WriteClipHull ();
  838.  
  839.     majorpercent += 32;
  840.  
  841.     MajorPercentBar(majorpercent*256/100);
  842. }
  843.  
  844. /*
  845. =================
  846. CreateHulls
  847.  
  848. =================
  849. */
  850. void CreateHulls (void)
  851. {
  852.     ShowStatusEntry("$f3Creating the hulls.");
  853.  
  854. /* commanded to create a single hull only */
  855.         if (hullnum)
  856.     {
  857.         ShowStatusEntry("$f3Creating a single hull.");
  858.                 CreateSingleHull ();
  859.         exit (0);
  860.     }
  861.     
  862. /* commanded to use the allready existing hulls 1 and 2 */
  863.     if (usehulls)
  864.     {
  865.         ShowStatusEntry("$f3Using existing hulls 1 and 2.");
  866.                 CreateSingleHull ();
  867.         return;
  868.     }
  869.     
  870. /* commanded to ignore the hulls altogether */
  871.     if (noclip)
  872.     {
  873.         ShowStatusEntry("$f3Ignoring hulls altogether.");
  874.                 CreateSingleHull ();
  875.         return;
  876.     }
  877.  
  878.  
  879. /* create all the hulls */
  880.  
  881. #ifdef __alpha
  882.  
  883.     ShowTempEntry("Forking hull processes.");
  884.     ShowTempEntry("(parallel hull calculations)");
  885.  
  886. /* fork a process for each clipping hull */
  887.     fflush (stdout);
  888.     if (!fork ())
  889.     {
  890.         hullnum = 1;
  891.         verbose = false;
  892.         drawflag = false;
  893.         sprintf (argv0, "HUL%i", hullnum);
  894.     }
  895.     else if (!fork ())
  896.     {
  897.         hullnum = 2;
  898.         verbose = false;
  899.         drawflag = false;
  900.         sprintf (argv0, "HUL%i", hullnum);
  901.     }
  902.     CreateSingleHull ();
  903.  
  904.     if (hullnum)
  905.         exit (0);
  906.     
  907.     wait (NULL);        /* wait for clip hull process to finish */
  908.     wait (NULL);        /* wait for clip hull process to finish */
  909.  
  910. #else
  911. /* create the hulls sequentially */
  912.     ShowTempEntry("Building hulls individually.");
  913.     ShowTempEntry("(not a multiprocessor system)");
  914.  
  915.     majorpercent = 2;
  916.     MajorPercentBar(2*256/100);
  917.  
  918.         ShowStatusEntry("$f3Creating hull 1.");
  919.         hullnum = 1;
  920.     CreateSingleHull ();
  921.     
  922.         ShowStatusEntry("$f3Creating hull 2.");
  923.         nummodels = 0;
  924.     numplanes = 0;
  925.     numclipnodes = 0;
  926.     hullnum = 2;
  927.     CreateSingleHull ();
  928.     
  929.         ShowStatusEntry("$f3Creating primary hull.");
  930.         nummodels = 0;
  931.     numplanes = 0;
  932.     numclipnodes = 0;
  933.     hullnum = 0;
  934.     CreateSingleHull ();
  935.  
  936.     majorpercent = 98;
  937.     MajorPercentBar(98*256/100);
  938. #endif  
  939.  
  940. }
  941.  
  942. /*
  943. =================
  944. ProcessFile
  945.  
  946. =================
  947. */
  948. void ProcessFile (char *sourcebase, char *bspfilename1)
  949. {
  950.     long int    diff;
  951.     char        *path, fullpath[1024];
  952.     FILE        *tempfile;
  953.  
  954.     majorpercent = 0;
  955.         MajorPercentBar(0);
  956.  
  957. /* create filenames */
  958.     strcpy (bspfilename, bspfilename1);
  959.     StripExtension (bspfilename);
  960.     strcat (bspfilename, ".bsp");
  961.  
  962.     strcpy (hullfilename, bspfilename1);
  963.     StripExtension (hullfilename);
  964.     strcat (hullfilename, ".h0");
  965.  
  966.     strcpy (portfilename, bspfilename1);
  967.     StripExtension (portfilename);
  968.     strcat (portfilename, ".prt");
  969.     
  970.     strcpy (pointfilename, bspfilename1);
  971.     StripExtension (pointfilename);
  972.     strcat (pointfilename, ".pts");
  973.  
  974.     strcpy (logfilename, bspfilename1);
  975.     StripExtension (logfilename);
  976.     strcat (logfilename, ".log");
  977.  
  978.     LogFile = fopen(logfilename, "wt");
  979.     fprintf(LogFile, "\n-------------------------------------------\n"
  980.              "*** BEGIN QBSP ***\n\n");
  981.  
  982.         if (!onlyents)
  983.     {
  984.         remove (bspfilename);
  985.         if (!usehulls)
  986.         {
  987.             hullfilename[strlen(hullfilename)-1] = '1';
  988.             remove (hullfilename);
  989.             hullfilename[strlen(hullfilename)-1] = '2';
  990.             remove (hullfilename);
  991.         }
  992.         remove (portfilename);
  993.         remove (pointfilename);
  994.     }
  995.     
  996. /* load brushes and entities */
  997.         LoadMapFile (sourcebase);
  998.     if (onlyents)
  999.     {
  1000.         UpdateEntLump ();
  1001.         return;
  1002.     }
  1003.     
  1004. /* Check to make sure there's a wad file in there */
  1005.     ShowTempEntry("Checking to find WAD file.");
  1006.  
  1007.         path = ValueForKey (&entities[0], "wad");
  1008.         if (!path || !path[0])
  1009.         Error("No wad file specified.");
  1010.     sprintf (fullpath, "%s%s", projectpath, path);
  1011.     if ((tempfile = fopen(fullpath, "rb")) == NULL)
  1012.         Error("Wad file %s not found.", fullpath);
  1013.         fclose(tempfile);               /* Okay, okay, just checking */
  1014.  
  1015. /* init the tables to be shared by all models */
  1016.         BeginBSPFile ();
  1017.  
  1018.     MajorPercentBar(2*256/100);
  1019.  
  1020. /* the clipping hulls will be written out to text files by forked processes */
  1021.     CreateHulls ();
  1022.  
  1023.     MajorPercentBar(98*256/100);
  1024.  
  1025.         ShowStatusEntry("Recombining hull data.");
  1026.  
  1027.         ReadClipHull (1);
  1028.     ReadClipHull (2);
  1029.  
  1030.     WriteEntitiesToString();
  1031.     FinishBSPFile ();
  1032.  
  1033.     MajorPercentBar(100*256/100);
  1034.  
  1035.         ShowStatusEntry("BSP file creation complete.");
  1036. }
  1037.  
  1038. /*
  1039. ==================
  1040. MakeProjectPath
  1041.  
  1042. If project path wasn't set with a command line, figure it out by the source
  1043. ==================
  1044. */
  1045. void MakeProjectPath (char *sourcebase)
  1046. {
  1047.     char    full[1024];
  1048.     char    *scan;
  1049.     int        l;
  1050.  
  1051.     if (projectpath[0])
  1052.     {    /* specified by hand, check for trailing slash */
  1053.         l = strlen (projectpath);
  1054.         if (projectpath[l-1] != '/')
  1055.             strcat (projectpath, "/");
  1056.     }
  1057.     else
  1058.     {        
  1059.         if (sourcebase[0] == '/')
  1060.             strcpy (full, sourcebase);
  1061.         else
  1062.         {
  1063. #ifdef _WIN32
  1064.             getcwd (full);
  1065. #else
  1066.          getwd (full);
  1067. #endif
  1068.             strcat (full, "/");
  1069.             strcat (full, sourcebase);
  1070.         }
  1071.         
  1072.     /* scan for the maps directory */
  1073.         scan = full;
  1074.         while (*scan)
  1075.         {
  1076.             if (!strncmp(scan, "maps", 4))
  1077.             {    /* take everything up to scan */
  1078.                 *scan = 0;
  1079.                 strcpy (projectpath, full);
  1080.                 break;
  1081.             }
  1082.             scan++;
  1083.         }
  1084.         if (!scan)
  1085.             Error ("Couldn't identify project directory from pathname.  Use -proj <path>");
  1086.     }
  1087.  
  1088.     ShowStatusEntry("ProjDir: \"%s\"", projectpath);
  1089. }
  1090.  
  1091. /*
  1092. ==================
  1093. main
  1094.  
  1095. ==================
  1096. */
  1097. int main (int argc, char **argv)
  1098. {
  1099.     int        i;
  1100.     double        start, end;
  1101.     char        sourcename[1024];
  1102.     char        destname[1024];
  1103.     long int    diff;
  1104.     FILE        *tempfile;
  1105.  
  1106.         LogFile = NULL;
  1107.  
  1108. /*      malloc_debug (15); */
  1109.  
  1110. /* */
  1111. /* check command line flags */
  1112. /* */
  1113.     for (i=1 ; i<argc ; i++)
  1114.     {
  1115.         if (argv[i][0] != '-')
  1116.             break;
  1117.         else if (!strcmp (argv[i],"-draw"))
  1118.             drawflag = true;
  1119.         else if (!strcmp (argv[i],"-notjunc"))
  1120.             notjunc = true;
  1121.         else if (!strcmp (argv[i],"-nofill"))
  1122.             nofill = true;
  1123.         else if (!strcmp (argv[i],"-noclip"))
  1124.             noclip = true;
  1125.         else if (!strcmp (argv[i],"-onlyents"))
  1126.             onlyents = true;
  1127.         else if (!strcmp (argv[i],"-verbose"))
  1128.             allverbose = true;
  1129.         else if (!strcmp (argv[i],"-usehulls"))
  1130.             usehulls = true;        /* don't fork -- use the existing files */
  1131.         else if (!strcmp (argv[i],"-hullnum"))
  1132.         {
  1133.             if (++i < argc)
  1134.                 hullnum = atoi(argv[i]);
  1135.         }
  1136.         else if (!strcmp (argv[i],"-proj"))
  1137.         {
  1138.             if (++i < argc)
  1139.                 strcpy (projectpath, argv[i]);
  1140.         }
  1141.         else if (argv[i][1] == 'e' || argv[i][1] == 'l' || argv[i][1] == 'v') {
  1142.             int j = 1;
  1143.  
  1144.             while (argv[i][j] != '\0') {
  1145.                 switch (argv[i][j]) {
  1146.                 case 'e':
  1147.                     onlyents = 1;
  1148.                     j++;
  1149.                     break;
  1150.                 case 'l':
  1151.                     lightbsp = 1;
  1152.                     j++;
  1153.                     if (argv[i][j] == 'f') {
  1154.                         lightbspfast = 1;
  1155.                         j++;
  1156.                                         }
  1157.                                         break;
  1158.                 case 'v':
  1159.                     visbsp = 1;
  1160.                     j++;
  1161.                     if (argv[i][j] == 'f') {
  1162.                         visbspfast = 1;
  1163.                         j++;
  1164.                                         }
  1165.                                         break;
  1166.                 default:
  1167.                     fprintf(stderr, "QBSP: Unknown option \"%s\"\n", argv[i]);
  1168.                     while (argv[i][j] != '\0') j++;
  1169.                                         break;
  1170.                 }
  1171.                         }
  1172.                 }
  1173.                 else
  1174.             fprintf(stderr, "QBSP: Unknown option \"%s\"\n", argv[i]);
  1175.     }
  1176.     
  1177.     if (i != argc - 2 && i != argc - 1) {
  1178.         fprintf(stderr, "Usage:   qbsp [-nojunc] [-nofill] [-draw] [-onlyents] [-verbose]\n"
  1179.                 "              [-proj projectpath] [-<flags>] sourcefile [destfile]\n"
  1180.                 "\n"
  1181.                 "   -nojunc    Do not run tjunction\n"
  1182.                 "   -nofill    Do not fill outside or remove extra polygons\n"
  1183.                 "   -draw      ???\n"
  1184.                 "   -onlyents  Only update entity data; same as \"e\" flag\n"
  1185.                 "   -verbose   (Obsolete) Show verbose information\n"
  1186.                 "   -proj      Set project search path to <projectpath>\n"
  1187.                 "   -<flags>   Uses one or more of the following flags:\n"
  1188.                 "                e   Only update entity data; same as -onlyents\n"
  1189.                 "                l   Run \"light\" on the .BSP file\n"
  1190.                 "                lf  Run \"light -fast\" on the .BSP file\n"
  1191.                 "                v   Run \"vis\" on the .BSP file\n"
  1192.                 "                vf  Run \"vis -fast\" on the .BSP file\n"
  1193.         );
  1194.                 exit(-1);
  1195.         }
  1196.  
  1197.     strcpy (sourcename, argv[i]);
  1198.     DefaultExtension (sourcename, ".map");
  1199.     
  1200.     if ((tempfile = fopen(sourcename, "rt")) == NULL) {
  1201.         fprintf(stderr, "QBSP: Map file \"%s\" not found.\n", sourcename);
  1202.         exit(-1);
  1203.         }
  1204.     fclose(tempfile);
  1205.  
  1206.         ScrnInit();
  1207.     MoveCurs(2, 1);
  1208.         CPrintf("$b4$f7QBSP$f4 -");
  1209.  
  1210. /* */
  1211. /* let forked processes change name for ps status */
  1212. /* */
  1213.     argv0 = argv[0];
  1214.  
  1215.     MakeProjectPath (argv[i]);
  1216.     
  1217. /* */
  1218. /* create destination name if not specified */
  1219. /* */
  1220.     if (i != argc - 2)
  1221.     {
  1222.                 strcpy (destname, argv[i]);
  1223.         StripExtension (destname);
  1224.         strcat (destname, ".bsp");
  1225.     }
  1226.     else
  1227.         strcpy (destname, argv[i+1]);
  1228.  
  1229.     MoveCurs(9, 1);
  1230.     CPrintf("$f2%s", destname);
  1231.  
  1232.     if (lightbsp) {
  1233.         if (lightbspfast)
  1234.             ShowStatusEntry("$f3WILL$f7 light (fast) when done.");
  1235.         else
  1236.             ShowStatusEntry("$f3WILL$f7 light when done.");
  1237.         }
  1238.         else
  1239.          ShowStatusEntry("Will $f3NOT$f7 light when done.");
  1240.         if (visbsp) {
  1241.         if (visbspfast)
  1242.             ShowStatusEntry("$f3WILL$f7 vis (fast) when done.");
  1243.         else
  1244.             ShowStatusEntry("$f3WILL$f7 vis when done.");
  1245.     }
  1246.     else
  1247.          ShowStatusEntry("Will $f3NOT$f7 vis when done.");
  1248.  
  1249. /* */
  1250. /* do it! */
  1251. /* */
  1252.     ProcessFile (sourcename, destname);
  1253.  
  1254. #if 0
  1255.         SetBackColor(ANSI_GREEN);
  1256.     SetForeColor(ANSI_WHITE);
  1257.     DrawFilledBox(10, 8, 60, 5);
  1258.     MoveCurs(23, 9);
  1259.     CPrintf ("*** QBSP Completed Successfully ***");
  1260.     MoveCurs(12, 11);
  1261.     CPrintf("$f3Press any key to exit.");
  1262.  
  1263.     WaitKey();
  1264. #endif
  1265.  
  1266.         diff = LastCheck - StartTime;
  1267.     fprintf(LogFile, "\nQBSP completed successfully.  Elapsed time: %02d:%02d:%02d\n",
  1268.         diff / 360, (diff / 60) % 59, diff % 59);
  1269.     fprintf(LogFile, "-------------------------------------------\n\n");
  1270.         fclose(LogFile);
  1271.     LogFile = NULL;
  1272.  
  1273.     InitText();
  1274.         printf("QBSP completed successfully.  Elapsed time: %02d:%02d:%02d\n",
  1275.         diff / 360, (diff / 60) % 59, diff % 59);
  1276.  
  1277.         if (lightbsp) {
  1278.         printf("Running light...\n");
  1279.  
  1280.                 if (visbsp) {
  1281.             if (visbspfast) {
  1282.                 if (lightbspfast)
  1283.                     execlp("light", "light", "-vf", "-fast", destname, NULL);
  1284.                 else
  1285.                     execlp("light", "light", "-vf", destname, NULL);
  1286.                         }
  1287.             else {
  1288.                 if (lightbspfast)
  1289.                        execlp("light", "light", "-v", "-fast", destname, NULL);
  1290.                                 else
  1291.                        execlp("light", "light", "-v", destname, NULL);
  1292.             }
  1293.                 }
  1294.         else {
  1295.             if (lightbspfast)
  1296.                 execlp("light", "light", "-fast", destname, NULL);
  1297.             else
  1298.                 execlp("light", "light", destname, NULL);
  1299.                 }
  1300.         }
  1301.     else if (visbsp) {
  1302.         printf("Running vis...\n");
  1303.  
  1304.                 if (visbspfast)
  1305.             execlp("vis", "vis", "-fast", destname, NULL);
  1306.         else
  1307.             execlp("vis", "vis", destname, NULL);
  1308.         }
  1309.  
  1310.     return 0;
  1311. }
  1312.  
  1313.